//----------------------------------------------------------------------------
/** @file Interface.cpp
    This is the only file that includes C-headers from AmiGo and uses forward
    declarations for AmiGo functions and variables. */
//----------------------------------------------------------------------------
#include "stdafx.h"

#include "Interface.h"

#include <iostream>
#include <sstream>
#include <string>
#include "Board.h"
#include "GtpEngine.h"
#include "Platform.h"

#include "go.h"
#include "goplayutils.h"


//----------------------------------------------------------------------------


    // From goplayer.c
    extern short playLevel;
    extern short saveNLibs;
    extern char* playReason;
#if 0
    int genBord(enum bVal);
#endif
	extern void genState();
    short getMove(short* x, short* y);

    // From goplayutils.c
    extern short showTrees;
    extern short utilPlayLevel;
    extern sType mySType;
    extern short treeLibLim;
    extern short depthLimit;
    extern short playMark;
    extern intBoard bord;
    extern intBoard legal;
    extern intBoard ndbord;
    extern intBoard groupIDs;
    extern intBoard claim;
    extern intBoard connectMap;
    extern intBoard protPoints;
    extern intBoard sGroups;
    extern playRec playStack[];
    extern groupRec gList[];
    
    short saveable(short gx, short gy, short* savex, short* savey);

    // From killable.c
    short killable(short gx, short gy, short* killx, short* killy);

//----------------------------------------------------------------------------



/* Print moves on play stack to standard error in GoGui Live Gfx format.
   This function is exported as a C-function to be called in goplayutils.c
   if showTrees is true. See http://gogui.sf.net for a documentation of
   GoGui Live Gfx commands. */
void PrintGoGuiGfx()
{
    static std::string last = "";

    std::ostringstream buffer;
    buffer << "gogui-gfx: VAR ";
    for (int i = 0; i < playMark; ++i)
    {
        if (playStack[i].kind != add)
            continue;
        remAddRec* rec = &playStack[i].uval.add;
        if ((mySType == BLACK && rec->who == 1)
            || (mySType == WHITE && rec->who == -1))
            buffer << "B ";
        else
            buffer << "W ";
        buffer << amigogtp::Point(rec->xl, rec->yl) << ' ';
    }
    if (buffer.str() != last)
    {
        last = buffer.str();
        std::cerr << buffer.str() << std::endl;
    }
    amigogtp::Platform::Sleep(100);
}



//----------------------------------------------------------------------------

namespace
{

void GenBord(const amigogtp::Board& board, amigogtp::Color c)
{
    static int lastSize = -1;
    static amigogtp::ColorBoard lastColorBoard;
    static amigogtp::Color lastColor;

    int size = board.GetSize();
    assert(size >= 9 && size <= 19);
    assert(c == amigogtp::BLACK || c == amigogtp::WHITE);
    if (size == lastSize
        && board.GetPosition().GetColorBoard() == lastColorBoard
        && c == lastColor)
        return;
    lastSize = size;
    lastColorBoard = board.GetPosition().GetColorBoard();
    lastColor = c;

    int _maxPoint = size - 1;
    // Use the same setup as in the disabled genBord() in goplayer.c
    utilPlayLevel = playLevel;
    mySType = (c == amigogtp::BLACK ? BLACK : WHITE);
    if (playLevel < 2)
        treeLibLim = 2;
    else
        treeLibLim = 3;
    depthLimit = 100;
    for (int y = 0; y <= _maxPoint; ++y)
        for (int x = 0; x <= _maxPoint; ++x)
        {
            amigogtp::Point p(x, y);
            legal[x][y] = (board.IsLegal(p, c) ? TRUE : FALSE);
            if (board.GetColor(p) == c)
                bord[x][y] = 1;
            else if (board.GetColor(p) == amigogtp::EMPTY)
                bord[x][y] = 0;
            else
                bord[x][y] = -1;
        }
    genState();
}

void GenBord(amigogtp::Board& board)
{
    GenBord(board, board.GetToPlay());
}

} // namespace

//----------------------------------------------------------------------------

bool amigogtp::Interface::GetShowTrees()
{
    return (showTrees ? true : false);
}

void amigogtp::Interface::SetShowTrees(bool enable)
{
    showTrees = (enable ? TRUE : FALSE);
}

int amigogtp::Interface::GetPlayLevel()
{
    return playLevel;
}

void amigogtp::Interface::SetPlayLevel(int level)
{
    assert(level >= 0 && level <= 7);
    playLevel = level;
}

std::string amigogtp::Interface::GetPlayReason()
{
    if (playReason == 0)
        return "(null)";
    return playReason;
}

amigogtp::Point amigogtp::Interface::GenMove(Board& board, Color c)
{
    // Use the same setup as in the disabled genMove() in goplayer.c
    if (playLevel > 2)
        saveNLibs = TRUE;
    else
        saveNLibs = FALSE;
    GenBord(board, c);
    short x, y;
    if (getMove(&x, &y))
        return Point(x, y);
    return Point();
}

amigogtp::IntBoard amigogtp::Interface::GetIntBoard(Board& board, Color c,
                                                    const std::string& id)
{
    GenBord(board, c);
    intBoard* b;
    if (id == "claim")
        b = &claim;
    else if (id == "group_ids")
        b = &groupIDs;
    else if (id == "connect_map")
        b = &connectMap;
    else if (id == "ndbord")
        b = &ndbord;
    else if (id == "prot_points")
        b = &protPoints;
    else if (id == "sgroups")
        b = &sGroups;
    else
        throw GtpFailure() << "unknown int board: " << id;
    IntBoard result;
    for (int x = 0; x < board.GetSize(); ++x)
        for (int y = 0; y < board.GetSize(); ++y)
            result.Set(x, y, (*b)[x][y]);
    return result;
}

std::string amigogtp::Interface::GetGroupInfo(Board& board, Color c,
                                              const Point& p)
{
    GenBord(board, c);
    std::ostringstream buffer;
    groupRec rec = gList[groupIDs[p.GetX()][p.GetY()]];
    buffer << "Live  " << rec.isLive << '\n'
           << "Dead  " << rec.isDead << '\n'
           << "Libs  " << rec.libC << '\n'
           << "Eyes  " << rec.numEyes << '\n'
           << "Size  " << rec.size << '\n'
           << "Point " << Point(rec.lx, rec.ly) << '\n'
           << "Mark  " << rec.groupMark << '\n'
           << "Level " << rec.atLevel << '\n';
    return buffer.str();
}

bool amigogtp::Interface::IsKillable(Board& board, const Point& group,
                                     Point& move)
{
    GenBord(board);
    short x, y;
    if (killable(group.GetX(), group.GetY(), &x, &y))
    {
        move = Point(x, y);
        return true;
    }
    return false;
}

bool amigogtp::Interface::IsSaveable(Board& board, const Point& group,
                                     Point& move)
{
    GenBord(board);
    short x, y;
    if (saveable(group.GetX(), group.GetY(), &x, &y))
    {
        move = Point(x, y);
        return true;
    }
    return false;
}

//----------------------------------------------------------------------------
